﻿#include "../exercise.h"
#include <memory>

// READ: `std::shared_ptr` <https://zh.cppreference.com/w/cpp/memory/shared_ptr>
// READ: `std::weak_ptr` <https://zh.cppreference.com/w/cpp/memory/weak_ptr>

// TODO: 将下列 `?` 替换为正确的值
void TestSharedPtr() {
    auto shared = std::make_shared<int>(10);
    std::shared_ptr<int> ptrs[]{shared, shared, shared};

    std::weak_ptr<int> observer = shared;
    ASSERT(observer.use_count() == 4, "");  // shared + 3个数组元素

    ptrs[0].reset();
    ASSERT(observer.use_count() == 3, "");  // 减少1个

    ptrs[1] = nullptr;
    ASSERT(observer.use_count() == 2, "");  // 再减少1个

    ptrs[2] = std::make_shared<int>(*shared);  // 创建新对象，不再共享
    ASSERT(observer.use_count() == 1, "");     // 只有shared本身

    ptrs[0] = shared;
    ptrs[1] = shared;
    ptrs[2] = std::move(shared);  // shared变为nullptr，但ptr[2]接管
    ASSERT(observer.use_count() == 3, "");  // ptrs[0], ptrs[1], ptrs[2]

    std::ignore = std::move(ptrs[0]); // ptrs[0]变为nullptr
    ptrs[1] = std::move(ptrs[1]); // 自移动，无变化
    ptrs[1] = std::move(ptrs[2]);      // ptrs[2]不会变为nullptr，因为ptrs[1]和ptrs[2]本来就是指向同一个地址
    ASSERT(observer.use_count() == 2, "");  // ptrs[1], ptrs[2]

    shared = observer.lock();  // 创建新的shared_ptr
    ASSERT(observer.use_count() == 3, "");  // shared + ptrs[1], ptrs[2]

    shared = nullptr;
    for (auto &ptr : ptrs) ptr = nullptr;
    ASSERT(observer.use_count() == 0, "");  // 所有shared_ptr都释放了

    shared = observer.lock();  // 尝试获取，但对象已释放
    ASSERT(observer.use_count() == 0, "");  // 仍然为0
}

// NOTICE: shared_ptr 的循环引用问题
class A;
class B;
struct A {
    std::shared_ptr<B> ptr;
    ~A() { std::cout << "A destroyed" << std::endl; }
};
struct B {
    std::shared_ptr<A> ptr;
    ~B() { std::cout << "B destroyed" << std::endl; }
};

void TestSharedPtrCycle() {
    // TODO： 写一个测试用例，展示 shared_ptr 的循环引用问题
    // NOTICE：使用 `std::weak_ptr` 可以解决循环引用问题。

    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();
    
    // 创建循环引用
    a->ptr = b;
    b->ptr = a;
    
    std::cout << "A use_count: " << a.use_count() << std::endl;  // 2
    std::cout << "B use_count: " << b.use_count() << std::endl;  // 2
    
    // 离开作用域时，由于循环引用，A和B都不会被销毁
    // 不会输出 "A destroyed" 和 "B destroyed"
}


// 使用 weak_ptr 解决循环引用
struct A_Fixed;
struct B_Fixed;
struct A_Fixed {
    std::weak_ptr<B_Fixed> ptr;  // 使用weak_ptr打破循环
    ~A_Fixed() { std::cout << "A_Fixed destroyed" << std::endl; }
};
struct B_Fixed {
    std::weak_ptr<A_Fixed> ptr;  // 使用weak_ptr打破循环
    ~B_Fixed() { std::cout << "B_Fixed destroyed" << std::endl; }
};

void TestWeakPtrSolution() {
    auto a = std::make_shared<A_Fixed>();
    auto b = std::make_shared<B_Fixed>();
    
    a->ptr = b;
    b->ptr = a;
    
    std::cout << "A_Fixed use_count: " << a.use_count() << std::endl;  // 1
    std::cout << "B_Fixed use_count: " << b.use_count() << std::endl;  // 1
    
    // 离开作用域时，A和B都会被正确销毁
    // 会输出 "A_Fixed destroyed" 和 "B_Fixed destroyed"
}

template<typename T>
class MySharedPtr {
    // TODO: 实现 shared_ptr 的基本功能
    // NOTICE: 面试时经常会问到 shared_ptr 的实现原理，建议自己独立实现一个简单的 shared_ptr。
    // 例如，构造函数、析构函数、移动构造函数、移动赋值运算符等。

private:
    T* ptr = nullptr;
    int* ref_count = nullptr;

    void release() {
        if (ref_count) {
            --(*ref_count);
            if (*ref_count == 0) {
                delete ptr;
                delete ref_count;
            }
        }
        ptr = nullptr;
        ref_count = nullptr;
    }

public:
    // 构造函数
    explicit MySharedPtr(T* p = nullptr) : ptr(p), ref_count(p ? new int(1) : nullptr) {}
    
    // 拷贝构造函数
    MySharedPtr(const MySharedPtr& other) : ptr(other.ptr), ref_count(other.ref_count) {
        if (ref_count) {
            ++(*ref_count);
        }
    }
    
    // 移动构造函数
    MySharedPtr(MySharedPtr&& other) noexcept : ptr(other.ptr), ref_count(other.ref_count) {
        other.ptr = nullptr;
        other.ref_count = nullptr;
    }
    
    // 析构函数
    ~MySharedPtr() {
        release();
    }
    
    // 拷贝赋值运算符
    MySharedPtr& operator=(const MySharedPtr& other) {
        if (this != &other) {
            release();
            ptr = other.ptr;
            ref_count = other.ref_count;
            if (ref_count) {
                ++(*ref_count);
            }
        }
        return *this;
    }
    
    // 移动赋值运算符
    MySharedPtr& operator=(MySharedPtr&& other) noexcept {
        if (this != &other) {
            release();
            ptr = other.ptr;
            ref_count = other.ref_count;
            other.ptr = nullptr;
            other.ref_count = nullptr;
        }
        return *this;
    }
    
    // 访问操作符
    T* operator->() const { return ptr; }
    T& operator*() const { return *ptr; }
    
    // 获取原始指针
    T* get() const { return ptr; }
    
    // 获取引用计数
    int use_count() const { return ref_count ? *ref_count : 0; }
    
    // 布尔转换
    explicit operator bool() const { return ptr != nullptr; }
    
    // 重置
    void reset(T* p = nullptr) {
        release();
        ptr = p;
        ref_count = p ? new int(1) : nullptr;
    }
};

int main(int argc, char **argv) {
    TestSharedPtr();
    TestSharedPtrCycle();

    std::cout << "=== Testing shared_ptr cycle reference ===" << std::endl;
    TestSharedPtrCycle();
    
    std::cout << "=== Testing weak_ptr solution ===" << std::endl;
    TestWeakPtrSolution();    

    // NOTICE: 在这里使用自己实现的 shared_ptr
    MySharedPtr<int> ptr = MySharedPtr<int>(new int(10));
    MySharedPtr<int> ptr2 = ptr;
    MySharedPtr<int> ptr3 = std::move(ptr);
    ptr = ptr2;
    ptr = std::move(ptr3);

    // TODO: 将下列 `?` 替换为正确的值
    ASSERT(ptr.use_count() == 2, "");   // ptr 和 ptr2 共享
    ASSERT(ptr2.use_count() == 2, "");  // ptr 和 ptr2 共享
    ASSERT(ptr3.use_count() == 0, "");  // ptr3 被移动，为空
    return 0;
}




/*
`std::shared_ptr`

`std::weak_ptr`


方法思路
理解引用计数：shared_ptr通过引用计数管理共享所有权
weak_ptr的作用：观察共享对象而不增加引用计数，解决循环引用
实现原理：引用计数块与对象分离管理


运行结果：
A use_count: 2
B use_count: 2
=== Testing shared_ptr cycle reference ===
A use_count: 2
B use_count: 2
=== Testing weak_ptr solution ===
A_Fixed use_count: 1
B_Fixed use_count: 1
B_Fixed destroyed
A_Fixed destroyed
=================
exercise31 passed




代码解释
1. 引用计数测试
TestSharedPtr() 函数展示了 shared_ptr 的引用计数行为：

初始时有4个共享指针（1个原始 + 3个数组元素）
通过 reset() 和赋值减少引用计数
weak_ptr 可以观察但不影响引用计数
2. 循环引用问题
问题代码：

struct A {
    std::shared_ptr<B> ptr;  // 强引用
};
struct B {
    std::shared_ptr<A> ptr;  // 强引用
};
问题：A和B互相持有强引用，导致引用计数永远≥1，无法释放

解决方案：使用 weak_ptr 打破循环

struct A_Fixed {
    std::weak_ptr<B_Fixed> ptr;  // 弱引用，不增加计数
};
3. MySharedPtr 实现
核心机制：

分离存储：对象指针和引用计数指针分开
拷贝构造/赋值：增加引用计数
移动构造/赋值：转移所有权，原指针置空
析构函数：减少引用计数，计数为0时释放资源
关键方法：

void release() {
    if (ref_count) {
        --(*ref_count);
        if (*ref_count == 0) {
            delete ptr;
            delete ref_count;
        }
    }
    ptr = nullptr;
    ref_count = nullptr;
}
重要概念
shared_ptr 的特点
共享所有权：多个指针可以共享同一对象
自动管理：引用计数为0时自动释放
线程安全：引用计数操作是原子的（但对象访问需要额外同步）
weak_ptr 的作用
观察而不拥有：可以观察对象是否存在，但不增加引用计数
解决循环引用：打破强引用循环
临时访问：通过 lock() 方法获取临时所有权
性能考虑
内存开销：每个 shared_ptr 需要额外的控制块（通常16-24字节）
原子操作：引用计数修改需要原子操作，有一定性能开销
缓存局部性：对象和控制块分离，可能影响缓存性能
最佳实践
优先使用 make_shared：更高效，单次内存分配
避免循环引用：使用 weak_ptr 打破循环
谨慎使用原始指针：避免与 shared_ptr 混用导致重复释放
考虑性能：在性能关键代码中评估 shared_ptr 的开销
测试验证
程序运行后会通过所有测试：

引用计数行为正确
循环引用问题展示正确
自定义 MySharedPtr 功能正确
这个练习深入理解了 shared_ptr 和 weak_ptr 的工作原理和使用场景。
*/